//
// Created by Dell on 2021/5/27.
//
#include "utils.h"

unsigned char *LoadFileContent(AAssetManager *aAssetManager ,const char *path, int &filesSize) {

    unsigned char *fileContent = nullptr;
    filesSize = 0;
    AAsset *asset = AAssetManager_open(aAssetManager, path, AASSET_MODE_UNKNOWN);
    if (asset == nullptr) {
        LOGE("LoadFileContent asset is null, load shader error ");
        return nullptr;
    }
    filesSize = AAsset_getLength(asset);
    LOGE("LoadFileContent filesSize ...%d", filesSize);
    fileContent = new unsigned char[filesSize];
    AAsset_read(asset, fileContent, filesSize);
    fileContent[filesSize] = '\0';
    AAsset_close(asset);
    LOGE("LoadFileContent success ...%s", path);
    return fileContent;
}

GLuint CompileShader(GLenum shaderType, const char *shaderCode) {
    //显存中创建一个着色器，取得着色器id
    GLuint shader = glCreateShader(shaderType);
    //设置着色器代码
    //1 表示多少句代码，所有代码都放着。第三个表示如果多句代码，则要与前面的代码的长度。
    glShaderSource(shader, 1, &shaderCode, nullptr);
    //编译着色器代码
    glCompileShader(shader);

    GLint compileResult = GL_TRUE;
    // 查看编译状态
    glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
    if (compileResult == GL_FALSE) {
        char szLog[1024] = {0};
        GLsizei logLen = 0;// 存储日志长度
        glGetShaderInfoLog(shader, 1024, &logLen, szLog);//1024 为日志的最大长度
        LOGE("compile error , log: %s", szLog);
        LOGE("compile error ,shader %s", shaderCode);
        glDeleteShader(shader);
        return 0;
    }
    return shader;

}

GLuint CreateProgram(GLuint vsShader, GLuint fsShader) {
    //创建一个渲染程序，取得该程序id用于操作
    GLuint program = glCreateProgram();
    //绑定顶点着色器、片段着色器
    glAttachShader(program, vsShader);
    glAttachShader(program, fsShader);
    //gl链接到当前渲染程序
    glLinkProgram(program);
    //解除顶点着色器与片段着色器绑定
    glDetachShader(program, vsShader);
    glDetachShader(program, fsShader);
    GLint nResult;
    //查询渲染程序的链接状态
    glGetProgramiv(program, GL_LINK_STATUS, &nResult);
    if (nResult == GL_FALSE) {
        //未链接，输出错误日志，删除渲染程序
        char log[1024] = {0};
        GLsizei len = 0;// 存储日志长度
        glGetShaderInfoLog(program, 1024, &len, log);//1024 为日志的最大长度
        LOGE("create program error , log: %s", log);
        glDeleteProgram(program);
        return 0;
    }
    LOGE("create program success  ");
    return program;
}


GLuint CreateTexture2D(unsigned char *pixelData, int width, int height, GLenum type) {
    //纹理id
    GLuint texture;
    //在显存中申请一个纹理id
    glGenTextures(1, &texture);
    //绑定gl要操作的纹理,后续对该纹理进行设定
    glBindTexture(GL_TEXTURE_2D, texture);
    //纹理缩放时，读取颜色插值处理
    //GL_LINEAR 表示线性过滤，即该点的颜色由附近的点加权计算得到
    //GL_NEAREST 表示该点的颜色，直接由最靠近它的点颜色决定
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// 表示图像放大时候，使用线性过滤
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);// 表示图像缩小时候，使用线性过滤
    // 指定纹理坐标超出纹理边界时，怎么读取纹理数值
    // GL_REPEAT重复，相当于坐标对纹理宽度求于后读取纹理
    // GL_CLAMP 直接取纹理边界的颜色
    // GL_CLAMP_TO_EDGE 忽略边框，取纹理边缘的颜色
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    // 设置纹理数据
    glTexImage2D(GL_TEXTURE_2D, 0, type, width, height, 0, type, GL_UNSIGNED_BYTE,
                 pixelData);//GL_RGB
    //解除gl当前绑定的2d纹理
    glBindTexture(GL_TEXTURE_2D, 0);
    return texture;
}

unsigned char *DecodeBMP(unsigned char *bmpFileData, int &width, int &height) {
    if (0x4D42 == *((unsigned short *) bmpFileData)) { // 数据头是否为0x4D42 判断是否是 24位的位图,
        // 读格式头
        int pixelDataOffset = *((int *) (bmpFileData + 10));// 取出 像素数据在内存块的偏移地址
        width = *((int *) (bmpFileData + 18));
        height = *((int *) (bmpFileData + 22));
        unsigned char *pixelData = bmpFileData + pixelDataOffset;
        // 位图 像素数据 是 bgr排布的，所以 更换 r b的位置
        for (int i = 0; i < width * height * 3; i += 3) {
            unsigned char temp = pixelData[i];
            pixelData[i] = pixelData[i + 2];
            pixelData[i + 2] = temp;
        }
        LOGE("DecodeBMP success ");
        return pixelData;
    }
    LOGE("DecodeBMP error ");
    return nullptr;
}

GLuint CreateTextureFromBMP(AAssetManager *aAssetManager ,const char *bmpPath) {
    //读入纹理文件内容
    int nFileSize = 0;
    unsigned char *bmpFileContent = LoadFileContent(aAssetManager,bmpPath, nFileSize);
    if (bmpFileContent == NULL) {
        return 0;
    }
    //解码BMP文件，读取出RGB像素值
    int bmpWidth = 0, bmpHeight = 0;
    unsigned char *pixelData = DecodeBMP(bmpFileContent, bmpWidth, bmpHeight);
    if (pixelData == NULL) {
        delete[] bmpFileContent;
        LOGE("CreateTextureFromBMP error ");
        return 0;
    }
    //gl显存载入2d纹理，返回纹理id
    GLuint texture = CreateTexture2D(pixelData, bmpWidth, bmpHeight, GL_RGB);
    delete[] bmpFileContent;
    LOGE("CreateTextureFromBMP success %d %d", bmpWidth, bmpHeight);
    return texture;
}